Files
sprocket-formulas/src/bool_formula.rs
2024-04-17 12:08:08 +02:00

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(&regex).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);
}
}