1533 lines
52 KiB
Rust
1533 lines
52 KiB
Rust
use bigdecimal::BigDecimal;
|
|
use regex::Regex;
|
|
|
|
use crate::formula_reader::FormulaReader;
|
|
use crate::formula_string::FormulaString;
|
|
use crate::formula_string::OperatorPriority;
|
|
use crate::formula_writer::FormulaWriter;
|
|
use crate::generic::*;
|
|
use crate::types::*;
|
|
use crate::value::EnumValueFormula;
|
|
use crate::{
|
|
BoolArrayFormula, BoolFormula, DateArrayFormula, DateFormula, DateFormulas,
|
|
DateTimeArrayFormula, DateTimeFormula, DateTimeFormulas, DecimalArrayFormula, DecimalFormula,
|
|
DecimalFormulas, DeserializationError, DeserializedResult, ExecutionResult, Formula,
|
|
FormulaContext, IntArrayFormula, IntFormula, IntFormulas, ObjectArrayFormula, ObjectFormula,
|
|
StringArrayFormula, StringFormula, StringFormulas,
|
|
};
|
|
|
|
const BOOL_OP_FALSE: u8 = 0x10;
|
|
const BOOL_OP_TRUE: u8 = 0x11;
|
|
const BOOL_OP_NOT: u8 = 0x12;
|
|
const BOOL_OP_AND: u8 = 0x13;
|
|
const BOOL_OP_OR: u8 = 0x14;
|
|
const BOOL_OP_XOR: u8 = 0x15;
|
|
const BOOL_OP_COMPARE_INT: u8 = 0x16;
|
|
const BOOL_OP_COMPARE_DECIMAL: u8 = 0x17;
|
|
const BOOL_OP_COMPARE_STRING: u8 = 0x18;
|
|
const BOOL_OP_COMPARE_DATE: u8 = 0x19;
|
|
const BOOL_OP_COMPARE_DATETIME: u8 = 0x1A;
|
|
const BOOL_OP_MATCH_STRING_REGEX: u8 = 0x1B;
|
|
const BOOL_EMPTY_BOOLARRAY: u8 = 0x1C;
|
|
const BOOL_EMPTY_INTARRAY: u8 = 0x1D;
|
|
const BOOL_EMPTY_DECIMALARRAY: u8 = 0x1E;
|
|
const BOOL_EMPTY_STRINGARRAY: u8 = 0x1F;
|
|
const BOOL_EMPTY_DATEARRAY: u8 = 0x20;
|
|
const BOOL_EMPTY_DATETIMEARRAY: u8 = 0x21;
|
|
const BOOL_EMPTY_OBJECTARRAY: u8 = 0x22;
|
|
|
|
pub struct BoolFormulas {}
|
|
|
|
impl BoolFormulas {
|
|
pub fn from_bytes(bytes: &[u8]) -> Result<BoolFormula, DeserializationError> {
|
|
let mut reader = FormulaReader::new(bytes);
|
|
Self::from_reader(&mut reader)
|
|
}
|
|
|
|
pub fn from_reader(reader: &mut FormulaReader) -> Result<BoolFormula, DeserializationError> {
|
|
let operator = reader.read_byte()?;
|
|
match operator {
|
|
GENERIC_OP_INVALID => InvalidFormula::<BoolType>::deserialize(reader),
|
|
GENERIC_OP_DEFINE_LOCALS => DefineLocals::<BoolType>::deserialize(reader),
|
|
GENERIC_OP_LOCAL => LocalVariable::<BoolType>::deserialize(reader),
|
|
GENERIC_OP_OBJECT_FIELD => ObjectField::<BoolType>::deserialize(reader),
|
|
GENERIC_OP_OBJECT_METHOD_CALL => ObjectMethodCall::<BoolType>::deserialize(reader),
|
|
GENERIC_OP_ARRAY_ELEMENT => ArrayElement::<BoolType>::deserialize(reader),
|
|
GENERIC_OP_ARRAY_ELEMENT_OR_DEFAULT => {
|
|
ArrayElementOrDefault::<BoolType>::deserialize(reader)
|
|
}
|
|
GENERIC_OP_ARRAY_FIRST => ArrayFirst::<BoolType>::deserialize(reader),
|
|
GENERIC_OP_ARRAY_LAST => ArrayLast::<BoolType>::deserialize(reader),
|
|
GENERIC_OP_TERNARY => Ternary::<BoolType>::deserialize(reader),
|
|
BOOL_OP_FALSE => Ok(Box::new(BoolFalse {})),
|
|
BOOL_OP_TRUE => Ok(Box::new(BoolTrue {})),
|
|
BOOL_OP_NOT => BoolNot::deserialize(reader),
|
|
BOOL_OP_AND => BoolAnd::deserialize(reader),
|
|
BOOL_OP_OR => BoolOr::deserialize(reader),
|
|
BOOL_OP_XOR => BoolXor::deserialize(reader),
|
|
BOOL_OP_COMPARE_INT => BoolCompareInt::deserialize(reader),
|
|
BOOL_OP_COMPARE_DECIMAL => BoolCompareDecimal::deserialize(reader),
|
|
BOOL_OP_COMPARE_DATE => BoolCompareDate::deserialize(reader),
|
|
BOOL_OP_COMPARE_DATETIME => BoolCompareDateTime::deserialize(reader),
|
|
BOOL_OP_COMPARE_STRING => BoolCompareString::deserialize(reader),
|
|
BOOL_OP_MATCH_STRING_REGEX => BoolMatchStringRegex::deserialize(reader),
|
|
BOOL_EMPTY_BOOLARRAY => EmptyArray::<BoolType>::deserialize(reader),
|
|
BOOL_EMPTY_INTARRAY => EmptyArray::<IntType>::deserialize(reader),
|
|
BOOL_EMPTY_DECIMALARRAY => EmptyArray::<DecimalType>::deserialize(reader),
|
|
BOOL_EMPTY_STRINGARRAY => EmptyArray::<StringType>::deserialize(reader),
|
|
BOOL_EMPTY_DATEARRAY => EmptyArray::<DateType>::deserialize(reader),
|
|
BOOL_EMPTY_DATETIMEARRAY => EmptyArray::<DateTimeType>::deserialize(reader),
|
|
BOOL_EMPTY_OBJECTARRAY => EmptyArray::<ObjectType>::deserialize(reader),
|
|
other => Err(DeserializationError::UnknownOperator(Type::Bool, other)),
|
|
}
|
|
}
|
|
|
|
pub fn invalid(formula: String) -> BoolFormula {
|
|
InvalidFormula::<BoolType>::new(formula)
|
|
}
|
|
|
|
pub fn define_locals(locals: Vec<LocalDefinition>, formula: BoolFormula) -> BoolFormula {
|
|
DefineLocals::<BoolType>::new(locals, formula)
|
|
}
|
|
|
|
pub fn local(index: u32) -> BoolFormula {
|
|
LocalVariable::<BoolType>::new(index)
|
|
}
|
|
|
|
pub fn object_field(object: ObjectFormula, field: String) -> BoolFormula {
|
|
ObjectField::<BoolType>::new(object, field)
|
|
}
|
|
|
|
pub fn object_method_call(
|
|
object: ObjectFormula,
|
|
method: String,
|
|
arguments: Vec<EnumValueFormula>,
|
|
) -> BoolFormula {
|
|
ObjectMethodCall::<BoolType>::new(object, method, arguments)
|
|
}
|
|
|
|
pub fn array_element(array: BoolArrayFormula, index: IntFormula) -> BoolFormula {
|
|
ArrayElement::<BoolType>::new(array, index)
|
|
}
|
|
|
|
pub fn array_element_or_default(
|
|
array: BoolArrayFormula,
|
|
index: IntFormula,
|
|
default: BoolFormula,
|
|
) -> BoolFormula {
|
|
ArrayElementOrDefault::<BoolType>::new(array, index, default)
|
|
}
|
|
|
|
pub fn array_first(array: BoolArrayFormula) -> BoolFormula {
|
|
ArrayFirst::<BoolType>::new(array)
|
|
}
|
|
|
|
pub fn array_last(array: BoolArrayFormula) -> BoolFormula {
|
|
ArrayLast::<BoolType>::new(array)
|
|
}
|
|
|
|
pub fn ternary(
|
|
condition: BoolFormula,
|
|
true_value: BoolFormula,
|
|
false_value: BoolFormula,
|
|
) -> BoolFormula {
|
|
Ternary::<BoolType>::new(condition, true_value, false_value)
|
|
}
|
|
|
|
pub fn constant(value: bool) -> BoolFormula {
|
|
if value {
|
|
BoolTrue::new()
|
|
} else {
|
|
BoolFalse::new()
|
|
}
|
|
}
|
|
|
|
pub fn not(operand: BoolFormula) -> BoolFormula {
|
|
BoolNot::new(operand)
|
|
}
|
|
|
|
pub fn and(left: BoolFormula, right: BoolFormula) -> BoolFormula {
|
|
BoolAnd::new(left, right)
|
|
}
|
|
|
|
pub fn or(left: BoolFormula, right: BoolFormula) -> BoolFormula {
|
|
BoolOr::new(left, right)
|
|
}
|
|
|
|
pub fn xor(left: BoolFormula, right: BoolFormula) -> BoolFormula {
|
|
BoolXor::new(left, right)
|
|
}
|
|
|
|
pub fn compare_int(left: IntFormula, right: IntFormula, comparator: Comparator) -> BoolFormula {
|
|
BoolCompareInt::new(left, right, comparator)
|
|
}
|
|
|
|
pub fn compare_decimal(
|
|
left: DecimalFormula,
|
|
right: DecimalFormula,
|
|
comparator: Comparator,
|
|
) -> BoolFormula {
|
|
BoolCompareDecimal::new(left, right, comparator)
|
|
}
|
|
|
|
pub fn compare_string(
|
|
left: StringFormula,
|
|
right: StringFormula,
|
|
comparator: Comparator,
|
|
) -> BoolFormula {
|
|
BoolCompareString::new(left, right, comparator)
|
|
}
|
|
|
|
pub fn compare_date(
|
|
left: DateFormula,
|
|
right: DateFormula,
|
|
comparator: Comparator,
|
|
) -> BoolFormula {
|
|
BoolCompareDate::new(left, right, comparator)
|
|
}
|
|
|
|
pub fn compare_datetime(
|
|
left: DateTimeFormula,
|
|
right: DateTimeFormula,
|
|
comparator: Comparator,
|
|
) -> BoolFormula {
|
|
BoolCompareDateTime::new(left, right, comparator)
|
|
}
|
|
|
|
pub fn match_string_regex(string: StringFormula, regex: Regex) -> BoolFormula {
|
|
BoolMatchStringRegex::new(string, regex)
|
|
}
|
|
|
|
pub fn array_empty_bool(array: BoolArrayFormula) -> BoolFormula {
|
|
EmptyArray::<BoolType>::new(array)
|
|
}
|
|
|
|
pub fn array_empty_int(array: IntArrayFormula) -> BoolFormula {
|
|
EmptyArray::<IntType>::new(array)
|
|
}
|
|
|
|
pub fn array_empty_decimal(array: DecimalArrayFormula) -> BoolFormula {
|
|
EmptyArray::<DecimalType>::new(array)
|
|
}
|
|
|
|
pub fn array_empty_string(array: StringArrayFormula) -> BoolFormula {
|
|
EmptyArray::<StringType>::new(array)
|
|
}
|
|
|
|
pub fn array_empty_date(array: DateArrayFormula) -> BoolFormula {
|
|
EmptyArray::<DateType>::new(array)
|
|
}
|
|
|
|
pub fn array_empty_datetime(array: DateTimeArrayFormula) -> BoolFormula {
|
|
EmptyArray::<DateTimeType>::new(array)
|
|
}
|
|
|
|
pub fn array_empty_object(array: ObjectArrayFormula) -> BoolFormula {
|
|
EmptyArray::<ObjectType>::new(array)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum Comparator {
|
|
Equal,
|
|
NotEqual,
|
|
LessThan,
|
|
LessThanOrEqual,
|
|
GreaterThan,
|
|
GreaterThanOrEqual,
|
|
}
|
|
|
|
impl Comparator {
|
|
pub fn deserialize(value: u8) -> Result<Comparator, DeserializationError> {
|
|
match value {
|
|
0 => Ok(Comparator::Equal),
|
|
1 => Ok(Comparator::NotEqual),
|
|
2 => Ok(Comparator::LessThan),
|
|
3 => Ok(Comparator::LessThanOrEqual),
|
|
4 => Ok(Comparator::GreaterThan),
|
|
5 => Ok(Comparator::GreaterThanOrEqual),
|
|
other => Err(DeserializationError::UnknownComparator(other)),
|
|
}
|
|
}
|
|
|
|
pub fn serialize(&self) -> u8 {
|
|
match self {
|
|
Comparator::Equal => 0,
|
|
Comparator::NotEqual => 1,
|
|
Comparator::LessThan => 2,
|
|
Comparator::LessThanOrEqual => 3,
|
|
Comparator::GreaterThan => 4,
|
|
Comparator::GreaterThanOrEqual => 5,
|
|
}
|
|
}
|
|
|
|
pub fn to_string(&self) -> &'static str {
|
|
match self {
|
|
Comparator::Equal => "=",
|
|
Comparator::NotEqual => "!=",
|
|
Comparator::LessThan => "<",
|
|
Comparator::LessThanOrEqual => "<=",
|
|
Comparator::GreaterThan => ">",
|
|
Comparator::GreaterThanOrEqual => ">=",
|
|
}
|
|
}
|
|
}
|
|
|
|
struct BoolFalse {}
|
|
|
|
impl BoolFalse {
|
|
pub fn new() -> BoolFormula {
|
|
Box::new(Self {})
|
|
}
|
|
}
|
|
|
|
impl Formula<bool> for BoolFalse {
|
|
fn evaluate(&self, _context: &FormulaContext) -> ExecutionResult<bool> {
|
|
Ok(false)
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
writer.write_byte(BOOL_OP_FALSE);
|
|
}
|
|
|
|
fn to_formula_string(&self) -> FormulaString {
|
|
FormulaString::new("false".to_string(), OperatorPriority::Literal)
|
|
}
|
|
}
|
|
|
|
struct BoolTrue {}
|
|
|
|
impl BoolTrue {
|
|
pub fn new() -> BoolFormula {
|
|
Box::new(Self {})
|
|
}
|
|
}
|
|
|
|
impl Formula<bool> for BoolTrue {
|
|
fn evaluate(&self, _context: &FormulaContext) -> ExecutionResult<bool> {
|
|
Ok(true)
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
writer.write_byte(BOOL_OP_TRUE);
|
|
}
|
|
|
|
fn to_formula_string(&self) -> FormulaString {
|
|
FormulaString::new("true".to_string(), OperatorPriority::Literal)
|
|
}
|
|
}
|
|
|
|
struct BoolNot {
|
|
operand: BoolFormula,
|
|
}
|
|
|
|
impl BoolNot {
|
|
pub fn new(operand: BoolFormula) -> BoolFormula {
|
|
Box::new(Self { operand })
|
|
}
|
|
|
|
pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult<BoolFormula> {
|
|
let operand = BoolFormulas::from_reader(reader)?;
|
|
Ok(Box::new(Self { operand }))
|
|
}
|
|
}
|
|
|
|
impl Formula<bool> for BoolNot {
|
|
fn evaluate(&self, context: &FormulaContext) -> ExecutionResult<bool> {
|
|
let operand = self.operand.evaluate(context)?;
|
|
Ok(!operand)
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
writer.write_byte(BOOL_OP_NOT);
|
|
self.operand.serialize_to(writer);
|
|
}
|
|
|
|
fn to_formula_string(&self) -> FormulaString {
|
|
FormulaString::unary(self.operand.as_ref(), OperatorPriority::Unary, |operand| {
|
|
format!("!{}", operand)
|
|
})
|
|
}
|
|
}
|
|
|
|
struct BoolOr {
|
|
left: BoolFormula,
|
|
right: BoolFormula,
|
|
}
|
|
|
|
impl BoolOr {
|
|
pub fn new(left: BoolFormula, right: BoolFormula) -> BoolFormula {
|
|
Box::new(Self { left, right })
|
|
}
|
|
|
|
pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult<BoolFormula> {
|
|
let left = BoolFormulas::from_reader(reader)?;
|
|
let right = BoolFormulas::from_reader(reader)?;
|
|
Ok(Box::new(Self { left, right }))
|
|
}
|
|
}
|
|
|
|
impl Formula<bool> for BoolOr {
|
|
fn evaluate(&self, context: &FormulaContext) -> ExecutionResult<bool> {
|
|
let left = self.left.evaluate(context)?;
|
|
let right = self.right.evaluate(context)?;
|
|
Ok(left || right)
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
writer.write_byte(BOOL_OP_OR);
|
|
self.left.serialize_to(writer);
|
|
self.right.serialize_to(writer);
|
|
}
|
|
|
|
fn to_formula_string(&self) -> FormulaString {
|
|
FormulaString::binary(
|
|
self.left.as_ref(),
|
|
self.right.as_ref(),
|
|
OperatorPriority::Or,
|
|
|left, right| format!("{} || {}", left, right),
|
|
)
|
|
}
|
|
}
|
|
|
|
struct BoolAnd {
|
|
left: BoolFormula,
|
|
right: BoolFormula,
|
|
}
|
|
|
|
impl BoolAnd {
|
|
pub fn new(left: BoolFormula, right: BoolFormula) -> BoolFormula {
|
|
Box::new(Self { left, right })
|
|
}
|
|
|
|
pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult<BoolFormula> {
|
|
let left = BoolFormulas::from_reader(reader)?;
|
|
let right = BoolFormulas::from_reader(reader)?;
|
|
Ok(Box::new(Self { left, right }))
|
|
}
|
|
}
|
|
|
|
impl Formula<bool> for BoolAnd {
|
|
fn evaluate(&self, context: &FormulaContext) -> ExecutionResult<bool> {
|
|
let left = self.left.evaluate(context)?;
|
|
let right = self.right.evaluate(context)?;
|
|
Ok(left && right)
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
writer.write_byte(BOOL_OP_AND);
|
|
self.left.serialize_to(writer);
|
|
self.right.serialize_to(writer);
|
|
}
|
|
|
|
fn to_formula_string(&self) -> FormulaString {
|
|
FormulaString::binary(
|
|
self.left.as_ref(),
|
|
self.right.as_ref(),
|
|
OperatorPriority::And,
|
|
|left, right| format!("{} && {}", left, right),
|
|
)
|
|
}
|
|
}
|
|
|
|
struct BoolXor {
|
|
left: BoolFormula,
|
|
right: BoolFormula,
|
|
}
|
|
|
|
impl BoolXor {
|
|
pub fn new(left: BoolFormula, right: BoolFormula) -> BoolFormula {
|
|
Box::new(Self { left, right })
|
|
}
|
|
|
|
pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult<BoolFormula> {
|
|
let left = BoolFormulas::from_reader(reader)?;
|
|
let right = BoolFormulas::from_reader(reader)?;
|
|
Ok(Box::new(Self { left, right }))
|
|
}
|
|
}
|
|
|
|
impl Formula<bool> for BoolXor {
|
|
fn evaluate(&self, context: &FormulaContext) -> ExecutionResult<bool> {
|
|
let left = self.left.evaluate(context)?;
|
|
let right = self.right.evaluate(context)?;
|
|
Ok(left ^ right)
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
writer.write_byte(BOOL_OP_XOR);
|
|
self.left.serialize_to(writer);
|
|
self.right.serialize_to(writer);
|
|
}
|
|
|
|
fn to_formula_string(&self) -> FormulaString {
|
|
let left = self.left.to_formula_string();
|
|
let right = self.right.to_formula_string();
|
|
|
|
FormulaString::new(
|
|
format!(
|
|
"{} ^ {}",
|
|
left.wrap(OperatorPriority::Or),
|
|
right.wrap(OperatorPriority::Or)
|
|
),
|
|
OperatorPriority::Or,
|
|
)
|
|
}
|
|
}
|
|
|
|
struct BoolCompareInt {
|
|
left: IntFormula,
|
|
right: IntFormula,
|
|
comparator: Comparator,
|
|
}
|
|
|
|
impl BoolCompareInt {
|
|
pub fn new(left: IntFormula, right: IntFormula, comparator: Comparator) -> BoolFormula {
|
|
Box::new(Self {
|
|
left,
|
|
right,
|
|
comparator,
|
|
})
|
|
}
|
|
|
|
pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult<BoolFormula> {
|
|
let comparator = Comparator::deserialize(reader.read_byte()?)?;
|
|
let left = IntFormulas::from_reader(reader)?;
|
|
let right = IntFormulas::from_reader(reader)?;
|
|
Ok(Box::new(Self {
|
|
left,
|
|
right,
|
|
comparator,
|
|
}))
|
|
}
|
|
}
|
|
|
|
impl Formula<bool> for BoolCompareInt {
|
|
fn evaluate(&self, context: &FormulaContext) -> ExecutionResult<bool> {
|
|
let left = self.left.evaluate(context)?;
|
|
let right = self.right.evaluate(context)?;
|
|
|
|
match self.comparator {
|
|
Comparator::Equal => Ok(left == right),
|
|
Comparator::NotEqual => Ok(left != right),
|
|
Comparator::LessThan => Ok(left < right),
|
|
Comparator::LessThanOrEqual => Ok(left <= right),
|
|
Comparator::GreaterThan => Ok(left > right),
|
|
Comparator::GreaterThanOrEqual => Ok(left >= right),
|
|
}
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
writer.write_byte(BOOL_OP_COMPARE_INT);
|
|
writer.write_byte(self.comparator.serialize());
|
|
self.left.serialize_to(writer);
|
|
self.right.serialize_to(writer);
|
|
}
|
|
|
|
fn to_formula_string(&self) -> FormulaString {
|
|
let left = self.left.to_formula_string();
|
|
let right = self.right.to_formula_string();
|
|
|
|
FormulaString::new(
|
|
format!(
|
|
"{} {} {}",
|
|
left.wrap(OperatorPriority::Comparison),
|
|
self.comparator.to_string(),
|
|
right.wrap(OperatorPriority::Comparison)
|
|
),
|
|
OperatorPriority::Comparison,
|
|
)
|
|
}
|
|
}
|
|
|
|
struct BoolCompareDecimal {
|
|
left: Box<dyn Formula<BigDecimal>>,
|
|
right: Box<dyn Formula<BigDecimal>>,
|
|
comparator: Comparator,
|
|
}
|
|
|
|
impl BoolCompareDecimal {
|
|
pub fn new(
|
|
left: Box<dyn Formula<BigDecimal>>,
|
|
right: Box<dyn Formula<BigDecimal>>,
|
|
comparator: Comparator,
|
|
) -> BoolFormula {
|
|
Box::new(Self {
|
|
left,
|
|
right,
|
|
comparator,
|
|
})
|
|
}
|
|
|
|
pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult<BoolFormula> {
|
|
let comparator = Comparator::deserialize(reader.read_byte()?)?;
|
|
let left = DecimalFormulas::from_reader(reader)?;
|
|
let right = DecimalFormulas::from_reader(reader)?;
|
|
Ok(Box::new(Self {
|
|
left,
|
|
right,
|
|
comparator,
|
|
}))
|
|
}
|
|
}
|
|
|
|
impl Formula<bool> for BoolCompareDecimal {
|
|
fn evaluate(&self, context: &FormulaContext) -> ExecutionResult<bool> {
|
|
let left = self.left.evaluate(context)?;
|
|
let right = self.right.evaluate(context)?;
|
|
|
|
match self.comparator {
|
|
Comparator::Equal => Ok(left == right),
|
|
Comparator::NotEqual => Ok(left != right),
|
|
Comparator::LessThan => Ok(left < right),
|
|
Comparator::LessThanOrEqual => Ok(left <= right),
|
|
Comparator::GreaterThan => Ok(left > right),
|
|
Comparator::GreaterThanOrEqual => Ok(left >= right),
|
|
}
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
writer.write_byte(BOOL_OP_COMPARE_DECIMAL);
|
|
writer.write_byte(self.comparator.serialize());
|
|
self.left.serialize_to(writer);
|
|
self.right.serialize_to(writer);
|
|
}
|
|
|
|
fn to_formula_string(&self) -> FormulaString {
|
|
let left = self.left.to_formula_string();
|
|
let right = self.right.to_formula_string();
|
|
|
|
FormulaString::new(
|
|
format!(
|
|
"{} {} {}",
|
|
left.wrap(OperatorPriority::Comparison),
|
|
self.comparator.to_string(),
|
|
right.wrap(OperatorPriority::Comparison)
|
|
),
|
|
OperatorPriority::Comparison,
|
|
)
|
|
}
|
|
}
|
|
|
|
struct BoolCompareString {
|
|
left: StringFormula,
|
|
right: StringFormula,
|
|
comparator: Comparator,
|
|
}
|
|
|
|
impl BoolCompareString {
|
|
pub fn new(left: StringFormula, right: StringFormula, comparator: Comparator) -> BoolFormula {
|
|
Box::new(Self {
|
|
left,
|
|
right,
|
|
comparator,
|
|
})
|
|
}
|
|
|
|
pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult<BoolFormula> {
|
|
let comparator = Comparator::deserialize(reader.read_byte()?)?;
|
|
let left = StringFormulas::from_reader(reader)?;
|
|
let right = StringFormulas::from_reader(reader)?;
|
|
Ok(Box::new(Self {
|
|
left,
|
|
right,
|
|
comparator,
|
|
}))
|
|
}
|
|
}
|
|
|
|
impl Formula<bool> for BoolCompareString {
|
|
fn evaluate(&self, context: &FormulaContext) -> ExecutionResult<bool> {
|
|
let left = self.left.evaluate(context)?;
|
|
let right = self.right.evaluate(context)?;
|
|
|
|
match self.comparator {
|
|
Comparator::Equal => Ok(left == right),
|
|
Comparator::NotEqual => Ok(left != right),
|
|
Comparator::LessThan => Ok(left < right),
|
|
Comparator::LessThanOrEqual => Ok(left <= right),
|
|
Comparator::GreaterThan => Ok(left > right),
|
|
Comparator::GreaterThanOrEqual => Ok(left >= right),
|
|
}
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
writer.write_byte(BOOL_OP_COMPARE_STRING);
|
|
writer.write_byte(self.comparator.serialize());
|
|
self.left.serialize_to(writer);
|
|
self.right.serialize_to(writer);
|
|
}
|
|
|
|
fn to_formula_string(&self) -> FormulaString {
|
|
let left = self.left.to_formula_string();
|
|
let right = self.right.to_formula_string();
|
|
|
|
FormulaString::new(
|
|
format!(
|
|
"{} {} {}",
|
|
left.wrap(OperatorPriority::Comparison),
|
|
self.comparator.to_string(),
|
|
right.wrap(OperatorPriority::Comparison)
|
|
),
|
|
OperatorPriority::Comparison,
|
|
)
|
|
}
|
|
}
|
|
|
|
struct BoolCompareDate {
|
|
left: DateFormula,
|
|
right: DateFormula,
|
|
comparator: Comparator,
|
|
}
|
|
|
|
impl BoolCompareDate {
|
|
pub fn new(left: DateFormula, right: DateFormula, comparator: Comparator) -> BoolFormula {
|
|
Box::new(Self {
|
|
left,
|
|
right,
|
|
comparator,
|
|
})
|
|
}
|
|
|
|
pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult<BoolFormula> {
|
|
let comparator = Comparator::deserialize(reader.read_byte()?)?;
|
|
let left = DateFormulas::from_reader(reader)?;
|
|
let right = DateFormulas::from_reader(reader)?;
|
|
Ok(Box::new(Self {
|
|
left,
|
|
right,
|
|
comparator,
|
|
}))
|
|
}
|
|
}
|
|
|
|
impl Formula<bool> for BoolCompareDate {
|
|
fn evaluate(&self, context: &FormulaContext) -> ExecutionResult<bool> {
|
|
let left = self.left.evaluate(context)?;
|
|
let right = self.right.evaluate(context)?;
|
|
|
|
match self.comparator {
|
|
Comparator::Equal => Ok(left == right),
|
|
Comparator::NotEqual => Ok(left != right),
|
|
Comparator::LessThan => Ok(left < right),
|
|
Comparator::LessThanOrEqual => Ok(left <= right),
|
|
Comparator::GreaterThan => Ok(left > right),
|
|
Comparator::GreaterThanOrEqual => Ok(left >= right),
|
|
}
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
writer.write_byte(BOOL_OP_COMPARE_DATE);
|
|
writer.write_byte(self.comparator.serialize());
|
|
self.left.serialize_to(writer);
|
|
self.right.serialize_to(writer);
|
|
}
|
|
|
|
fn to_formula_string(&self) -> FormulaString {
|
|
let left = self.left.to_formula_string();
|
|
let right = self.right.to_formula_string();
|
|
|
|
FormulaString::new(
|
|
format!(
|
|
"{} {} {}",
|
|
left.wrap(OperatorPriority::Comparison),
|
|
self.comparator.to_string(),
|
|
right.wrap(OperatorPriority::Comparison)
|
|
),
|
|
OperatorPriority::Comparison,
|
|
)
|
|
}
|
|
}
|
|
|
|
struct BoolCompareDateTime {
|
|
left: DateTimeFormula,
|
|
right: DateTimeFormula,
|
|
comparator: Comparator,
|
|
}
|
|
|
|
impl BoolCompareDateTime {
|
|
pub fn new(
|
|
left: DateTimeFormula,
|
|
right: DateTimeFormula,
|
|
comparator: Comparator,
|
|
) -> BoolFormula {
|
|
Box::new(Self {
|
|
left,
|
|
right,
|
|
comparator,
|
|
})
|
|
}
|
|
|
|
pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult<BoolFormula> {
|
|
let comparator = Comparator::deserialize(reader.read_byte()?)?;
|
|
let left = DateTimeFormulas::from_reader(reader)?;
|
|
let right = DateTimeFormulas::from_reader(reader)?;
|
|
Ok(Box::new(Self {
|
|
left,
|
|
right,
|
|
comparator,
|
|
}))
|
|
}
|
|
}
|
|
|
|
impl Formula<bool> for BoolCompareDateTime {
|
|
fn evaluate(&self, context: &FormulaContext) -> ExecutionResult<bool> {
|
|
let left = self.left.evaluate(context)?;
|
|
let right = self.right.evaluate(context)?;
|
|
|
|
match self.comparator {
|
|
Comparator::Equal => Ok(left == right),
|
|
Comparator::NotEqual => Ok(left != right),
|
|
Comparator::LessThan => Ok(left < right),
|
|
Comparator::LessThanOrEqual => Ok(left <= right),
|
|
Comparator::GreaterThan => Ok(left > right),
|
|
Comparator::GreaterThanOrEqual => Ok(left >= right),
|
|
}
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
writer.write_byte(BOOL_OP_COMPARE_DATETIME);
|
|
writer.write_byte(self.comparator.serialize());
|
|
self.left.serialize_to(writer);
|
|
self.right.serialize_to(writer);
|
|
}
|
|
|
|
fn to_formula_string(&self) -> FormulaString {
|
|
let left = self.left.to_formula_string();
|
|
let right = self.right.to_formula_string();
|
|
|
|
FormulaString::new(
|
|
format!(
|
|
"{} {} {}",
|
|
left.wrap(OperatorPriority::Comparison),
|
|
self.comparator.to_string(),
|
|
right.wrap(OperatorPriority::Comparison)
|
|
),
|
|
OperatorPriority::Comparison,
|
|
)
|
|
}
|
|
}
|
|
|
|
struct BoolMatchStringRegex {
|
|
string: StringFormula,
|
|
regex: Regex,
|
|
}
|
|
|
|
impl BoolMatchStringRegex {
|
|
pub fn new(string: StringFormula, regex: Regex) -> BoolFormula {
|
|
Box::new(Self { string, regex })
|
|
}
|
|
|
|
pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult<BoolFormula> {
|
|
let string = StringFormulas::from_reader(reader)?;
|
|
let regex = reader.read_string()?;
|
|
let regex = Regex::new(®ex).map_err(|_| DeserializationError::InvalidRegex(regex))?;
|
|
Ok(Box::new(Self { string, regex }))
|
|
}
|
|
}
|
|
|
|
impl Formula<bool> for BoolMatchStringRegex {
|
|
fn evaluate(&self, context: &FormulaContext) -> ExecutionResult<bool> {
|
|
let string = self.string.evaluate(context)?;
|
|
Ok(self.regex.is_match(&string))
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
writer.write_byte(BOOL_OP_MATCH_STRING_REGEX);
|
|
self.string.serialize_to(writer);
|
|
writer.write_string(&self.regex.as_str());
|
|
}
|
|
|
|
fn to_formula_string(&self) -> FormulaString {
|
|
FormulaString::new(
|
|
format!(
|
|
"{}.match({})",
|
|
self.string.to_string(),
|
|
self.regex.as_str().replace("/", r"\/")
|
|
),
|
|
OperatorPriority::Comparison,
|
|
)
|
|
}
|
|
}
|
|
|
|
struct EmptyArray<T: ScalarType> {
|
|
array: Box<dyn Formula<Vec<T::T>>>,
|
|
}
|
|
|
|
impl<T: ScalarType> EmptyArray<T> {
|
|
pub fn new(array: Box<dyn Formula<Vec<T::T>>>) -> BoolFormula {
|
|
Box::new(Self { array })
|
|
}
|
|
|
|
pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult<BoolFormula> {
|
|
let array = T::ARRAY::formula_from_reader(reader)?;
|
|
Ok(Self::new(array))
|
|
}
|
|
}
|
|
|
|
impl<T: ScalarType> Formula<bool> for EmptyArray<T> {
|
|
fn evaluate(&self, context: &FormulaContext) -> ExecutionResult<bool> {
|
|
let array = self.array.evaluate(context)?;
|
|
Ok(array.is_empty())
|
|
}
|
|
|
|
fn serialize_to(&self, writer: &mut FormulaWriter) {
|
|
let op = match T::TYPE {
|
|
Type::Bool => BOOL_EMPTY_BOOLARRAY,
|
|
Type::Int => BOOL_EMPTY_INTARRAY,
|
|
Type::Decimal => BOOL_EMPTY_DECIMALARRAY,
|
|
Type::String => BOOL_EMPTY_STRINGARRAY,
|
|
Type::Date => BOOL_EMPTY_DATEARRAY,
|
|
Type::DateTime => BOOL_EMPTY_DATETIMEARRAY,
|
|
Type::Object => BOOL_EMPTY_OBJECTARRAY,
|
|
_ => unreachable!(),
|
|
};
|
|
writer.write_byte(op);
|
|
self.array.serialize_to(writer);
|
|
}
|
|
|
|
fn to_formula_string(&self) -> crate::formula_string::FormulaString {
|
|
FormulaString::unary(self.array.as_ref(), OperatorPriority::Member, |array| {
|
|
format!("{}.empty", array)
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::{bool_formula::Comparator, object::TestObject, value::Value, ObjectFormulas};
|
|
|
|
#[test]
|
|
fn test_local() {
|
|
let formula = crate::BoolFormulas::local(0);
|
|
let mut context = crate::FormulaContext::new_with_empty_root();
|
|
context.locals.push(Value::Bool(true));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_object_field() {
|
|
let formula = crate::BoolFormulas::object_field(
|
|
crate::ObjectFormulas::root(),
|
|
"bool_true".to_string(),
|
|
);
|
|
let context = crate::FormulaContext::new(TestObject::new(1));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_object_call() {
|
|
let formula = crate::BoolFormulas::object_method_call(
|
|
crate::ObjectFormulas::root(),
|
|
"really".to_string(),
|
|
vec![],
|
|
);
|
|
let context = crate::FormulaContext::new(TestObject::new(1));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_false() {
|
|
let formula = crate::BoolFormulas::constant(false);
|
|
let context = crate::FormulaContext::new_with_empty_root();
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_true() {
|
|
let formula = crate::BoolFormulas::constant(true);
|
|
let context = crate::FormulaContext::new_with_empty_root();
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_not() {
|
|
let formula = crate::BoolFormulas::not(crate::BoolFormulas::constant(true));
|
|
let context = crate::FormulaContext::new_with_empty_root();
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_and() {
|
|
let formula = crate::BoolFormulas::and(
|
|
crate::BoolFormulas::constant(true),
|
|
crate::BoolFormulas::constant(false),
|
|
);
|
|
let context = crate::FormulaContext::new_with_empty_root();
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::and(
|
|
crate::BoolFormulas::constant(true),
|
|
crate::BoolFormulas::constant(true),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::and(
|
|
crate::BoolFormulas::constant(false),
|
|
crate::BoolFormulas::constant(false),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_or() {
|
|
let formula = crate::BoolFormulas::or(
|
|
crate::BoolFormulas::constant(true),
|
|
crate::BoolFormulas::constant(false),
|
|
);
|
|
let context = crate::FormulaContext::new_with_empty_root();
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::or(
|
|
crate::BoolFormulas::constant(true),
|
|
crate::BoolFormulas::constant(true),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::or(
|
|
crate::BoolFormulas::constant(false),
|
|
crate::BoolFormulas::constant(false),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_xor() {
|
|
let formula = crate::BoolFormulas::xor(
|
|
crate::BoolFormulas::constant(true),
|
|
crate::BoolFormulas::constant(false),
|
|
);
|
|
let context = crate::FormulaContext::new_with_empty_root();
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::xor(
|
|
crate::BoolFormulas::constant(true),
|
|
crate::BoolFormulas::constant(true),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::xor(
|
|
crate::BoolFormulas::constant(false),
|
|
crate::BoolFormulas::constant(false),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::xor(
|
|
crate::BoolFormulas::constant(false),
|
|
crate::BoolFormulas::constant(true),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_compare_int() {
|
|
let formula = crate::BoolFormulas::compare_int(
|
|
crate::IntFormulas::value(1),
|
|
crate::IntFormulas::value(2),
|
|
Comparator::Equal,
|
|
);
|
|
let context = crate::FormulaContext::new_with_empty_root();
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::compare_int(
|
|
crate::IntFormulas::value(1),
|
|
crate::IntFormulas::value(2),
|
|
Comparator::NotEqual,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::compare_int(
|
|
crate::IntFormulas::value(1),
|
|
crate::IntFormulas::value(2),
|
|
Comparator::LessThan,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::compare_int(
|
|
crate::IntFormulas::value(1),
|
|
crate::IntFormulas::value(2),
|
|
Comparator::LessThanOrEqual,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::compare_int(
|
|
crate::IntFormulas::value(1),
|
|
crate::IntFormulas::value(2),
|
|
Comparator::GreaterThan,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::compare_int(
|
|
crate::IntFormulas::value(1),
|
|
crate::IntFormulas::value(2),
|
|
Comparator::GreaterThanOrEqual,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::compare_int(
|
|
crate::IntFormulas::value(2),
|
|
crate::IntFormulas::value(2),
|
|
Comparator::Equal,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_compare_decimal() {
|
|
let formula = crate::BoolFormulas::compare_decimal(
|
|
crate::DecimalFormulas::value("1.0".parse().unwrap()),
|
|
crate::DecimalFormulas::value("2.0".parse().unwrap()),
|
|
Comparator::Equal,
|
|
);
|
|
let context = crate::FormulaContext::new_with_empty_root();
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::compare_decimal(
|
|
crate::DecimalFormulas::value("1.0".parse().unwrap()),
|
|
crate::DecimalFormulas::value("2.0".parse().unwrap()),
|
|
Comparator::NotEqual,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::compare_decimal(
|
|
crate::DecimalFormulas::value("1.0".parse().unwrap()),
|
|
crate::DecimalFormulas::value("2.0".parse().unwrap()),
|
|
Comparator::LessThan,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::compare_decimal(
|
|
crate::DecimalFormulas::value("1.0".parse().unwrap()),
|
|
crate::DecimalFormulas::value("2.0".parse().unwrap()),
|
|
Comparator::LessThanOrEqual,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::compare_decimal(
|
|
crate::DecimalFormulas::value("1.0".parse().unwrap()),
|
|
crate::DecimalFormulas::value("2.0".parse().unwrap()),
|
|
Comparator::GreaterThan,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::compare_decimal(
|
|
crate::DecimalFormulas::value("1.0".parse().unwrap()),
|
|
crate::DecimalFormulas::value("2.0".parse().unwrap()),
|
|
Comparator::GreaterThanOrEqual,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::compare_decimal(
|
|
crate::DecimalFormulas::value("1.0".parse().unwrap()),
|
|
crate::DecimalFormulas::value("2.0".parse().unwrap()),
|
|
Comparator::Equal,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_compare_date() {
|
|
let formula = crate::BoolFormulas::compare_date(
|
|
crate::DateFormulas::value("2020-01-01".parse().unwrap()),
|
|
crate::DateFormulas::value("2020-01-02".parse().unwrap()),
|
|
Comparator::Equal,
|
|
);
|
|
let context = crate::FormulaContext::new_with_empty_root();
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::compare_date(
|
|
crate::DateFormulas::value("2020-01-01".parse().unwrap()),
|
|
crate::DateFormulas::value("2020-01-02".parse().unwrap()),
|
|
Comparator::NotEqual,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::compare_date(
|
|
crate::DateFormulas::value("2020-01-01".parse().unwrap()),
|
|
crate::DateFormulas::value("2020-01-02".parse().unwrap()),
|
|
Comparator::LessThan,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::compare_date(
|
|
crate::DateFormulas::value("2020-01-01".parse().unwrap()),
|
|
crate::DateFormulas::value("2020-01-02".parse().unwrap()),
|
|
Comparator::LessThanOrEqual,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::compare_date(
|
|
crate::DateFormulas::value("2020-01-01".parse().unwrap()),
|
|
crate::DateFormulas::value("2020-01-02".parse().unwrap()),
|
|
Comparator::GreaterThan,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::compare_date(
|
|
crate::DateFormulas::value("2020-01-01".parse().unwrap()),
|
|
crate::DateFormulas::value("2020-01-02".parse().unwrap()),
|
|
Comparator::GreaterThanOrEqual,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_compare_datetime() {
|
|
let formula = crate::BoolFormulas::compare_datetime(
|
|
crate::DateTimeFormulas::value("2020-01-01T00:00:00Z".parse().unwrap()),
|
|
crate::DateTimeFormulas::value("2020-01-01T00:00:01Z".parse().unwrap()),
|
|
Comparator::Equal,
|
|
);
|
|
let context = crate::FormulaContext::new_with_empty_root();
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::compare_datetime(
|
|
crate::DateTimeFormulas::value("2020-01-01T00:00:00Z".parse().unwrap()),
|
|
crate::DateTimeFormulas::value("2020-01-01T00:00:01Z".parse().unwrap()),
|
|
Comparator::NotEqual,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::compare_datetime(
|
|
crate::DateTimeFormulas::value("2020-01-01T00:00:00Z".parse().unwrap()),
|
|
crate::DateTimeFormulas::value("2020-01-01T00:00:01Z".parse().unwrap()),
|
|
Comparator::LessThan,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::compare_datetime(
|
|
crate::DateTimeFormulas::value("2020-01-01T00:00:00Z".parse().unwrap()),
|
|
crate::DateTimeFormulas::value("2020-01-01T00:00:01Z".parse().unwrap()),
|
|
Comparator::LessThanOrEqual,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::compare_datetime(
|
|
crate::DateTimeFormulas::value("2020-01-01T00:00:00Z".parse().unwrap()),
|
|
crate::DateTimeFormulas::value("2020-01-01T00:00:01Z".parse().unwrap()),
|
|
Comparator::GreaterThan,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::compare_datetime(
|
|
crate::DateTimeFormulas::value("2020-01-01T00:00:00Z".parse().unwrap()),
|
|
crate::DateTimeFormulas::value("2020-01-01T00:00:01Z".parse().unwrap()),
|
|
Comparator::GreaterThanOrEqual,
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_match_string_regex() {
|
|
let formula = crate::BoolFormulas::match_string_regex(
|
|
crate::StringFormulas::value("abc".to_string()),
|
|
regex::Regex::new("abc").unwrap(),
|
|
);
|
|
let context = crate::FormulaContext::new_with_empty_root();
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::match_string_regex(
|
|
crate::StringFormulas::value("abc".to_string()),
|
|
regex::Regex::new("def").unwrap(),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::match_string_regex(
|
|
crate::StringFormulas::value("abc".to_string()),
|
|
regex::Regex::new("a.c").unwrap(),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::match_string_regex(
|
|
crate::StringFormulas::value("abc".to_string()),
|
|
regex::Regex::new("a.d").unwrap(),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::match_string_regex(
|
|
crate::StringFormulas::value("abc".to_string()),
|
|
regex::Regex::new("a.*c").unwrap(),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let formula = crate::BoolFormulas::match_string_regex(
|
|
crate::StringFormulas::value("abc".to_string()),
|
|
regex::Regex::new("a.*d").unwrap(),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::match_string_regex(
|
|
crate::StringFormulas::value("abc".to_string()),
|
|
regex::Regex::new("a.*").unwrap(),
|
|
);
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_bool_array_empty() {
|
|
let formula =
|
|
crate::BoolFormulas::array_empty_bool(crate::BoolArrayFormulas::object_field(
|
|
ObjectFormulas::root(),
|
|
"bool_array".to_string(),
|
|
));
|
|
let context = crate::FormulaContext::new(TestObject::new(1));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula =
|
|
crate::BoolFormulas::array_empty_bool(crate::BoolArrayFormulas::object_field(
|
|
ObjectFormulas::root(),
|
|
"empty_bool_array".to_string(),
|
|
));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_int_array_empty() {
|
|
let formula = crate::BoolFormulas::array_empty_int(crate::IntArrayFormulas::object_field(
|
|
ObjectFormulas::root(),
|
|
"int_array".to_string(),
|
|
));
|
|
let context = crate::FormulaContext::new(TestObject::new(1));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula = crate::BoolFormulas::array_empty_int(crate::IntArrayFormulas::object_field(
|
|
ObjectFormulas::root(),
|
|
"empty_int_array".to_string(),
|
|
));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_decimal_array_empty() {
|
|
let formula =
|
|
crate::BoolFormulas::array_empty_decimal(crate::DecimalArrayFormulas::object_field(
|
|
ObjectFormulas::root(),
|
|
"decimal_array".to_string(),
|
|
));
|
|
let context = crate::FormulaContext::new(TestObject::new(1));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula =
|
|
crate::BoolFormulas::array_empty_decimal(crate::DecimalArrayFormulas::object_field(
|
|
ObjectFormulas::root(),
|
|
"empty_decimal_array".to_string(),
|
|
));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_string_array_empty() {
|
|
let formula =
|
|
crate::BoolFormulas::array_empty_string(crate::StringArrayFormulas::object_field(
|
|
ObjectFormulas::root(),
|
|
"string_array".to_string(),
|
|
));
|
|
let context = crate::FormulaContext::new(TestObject::new(1));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula =
|
|
crate::BoolFormulas::array_empty_string(crate::StringArrayFormulas::object_field(
|
|
ObjectFormulas::root(),
|
|
"empty_string_array".to_string(),
|
|
));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_date_array_empty() {
|
|
let formula =
|
|
crate::BoolFormulas::array_empty_date(crate::DateArrayFormulas::object_field(
|
|
ObjectFormulas::root(),
|
|
"date_array".to_string(),
|
|
));
|
|
let context = crate::FormulaContext::new(TestObject::new(1));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula =
|
|
crate::BoolFormulas::array_empty_date(crate::DateArrayFormulas::object_field(
|
|
ObjectFormulas::root(),
|
|
"empty_date_array".to_string(),
|
|
));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_datetime_array_empty() {
|
|
let formula =
|
|
crate::BoolFormulas::array_empty_datetime(crate::DateTimeArrayFormulas::object_field(
|
|
ObjectFormulas::root(),
|
|
"datetime_array".to_string(),
|
|
));
|
|
let context = crate::FormulaContext::new(TestObject::new(1));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, false);
|
|
|
|
let formula =
|
|
crate::BoolFormulas::array_empty_datetime(crate::DateTimeArrayFormulas::object_field(
|
|
ObjectFormulas::root(),
|
|
"empty_datetime_array".to_string(),
|
|
));
|
|
let result = formula.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
|
|
let serialized = formula.serialize();
|
|
let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap();
|
|
let result = deserialized.evaluate(&context).unwrap();
|
|
assert_eq!(result, true);
|
|
}
|
|
}
|