dsq_shared/ops/
comparison_ops.rs

1//! Comparison operations
2//!
3//! This module contains value comparison operations for filtering and conditional logic.
4
5use crate::value::Value;
6use crate::Result;
7use std::any::Any;
8
9use super::traits::{Context, Operation};
10use super::utils::compare_values;
11
12/// Equality comparison operation
13///
14/// Compares two values for equality.
15pub struct EqOperation {
16    /// Operations that produce the left operand
17    pub left_ops: Vec<Box<dyn Operation + Send + Sync>>,
18    /// Operations that produce the right operand
19    pub right_ops: Vec<Box<dyn Operation + Send + Sync>>,
20}
21
22impl EqOperation {
23    /// Creates a new equality operation with the given operand operations
24    pub fn new(
25        left_ops: Vec<Box<dyn Operation + Send + Sync>>,
26        right_ops: Vec<Box<dyn Operation + Send + Sync>>,
27    ) -> Self {
28        Self {
29            left_ops,
30            right_ops,
31        }
32    }
33}
34
35impl Operation for EqOperation {
36    fn apply(&self, value: &Value) -> Result<Value> {
37        let mut context = None;
38        self.apply_with_context(value, &mut context)
39    }
40
41    fn apply_with_context(
42        &self,
43        value: &Value,
44        context: &mut Option<&mut dyn Context>,
45    ) -> Result<Value> {
46        let mut left_val = value.clone();
47        for op in &self.left_ops {
48            left_val = op.apply_with_context(&left_val, context)?;
49        }
50
51        let mut right_val = value.clone();
52        for op in &self.right_ops {
53            right_val = op.apply_with_context(&right_val, context)?;
54        }
55
56        Ok(Value::Bool(left_val == right_val))
57    }
58
59    fn description(&self) -> String {
60        "equals".to_string()
61    }
62
63    fn as_any(&self) -> &dyn Any {
64        self
65    }
66}
67
68/// Inequality comparison operation
69///
70/// Compares two values for inequality.
71pub struct NeOperation {
72    /// Operations that produce the left operand
73    pub left_ops: Vec<Box<dyn Operation + Send + Sync>>,
74    /// Operations that produce the right operand
75    pub right_ops: Vec<Box<dyn Operation + Send + Sync>>,
76}
77
78impl NeOperation {
79    /// Creates a new inequality operation with the given operand operations
80    pub fn new(
81        left_ops: Vec<Box<dyn Operation + Send + Sync>>,
82        right_ops: Vec<Box<dyn Operation + Send + Sync>>,
83    ) -> Self {
84        Self {
85            left_ops,
86            right_ops,
87        }
88    }
89}
90
91impl Operation for NeOperation {
92    fn apply(&self, value: &Value) -> Result<Value> {
93        let mut context = None;
94        self.apply_with_context(value, &mut context)
95    }
96
97    fn apply_with_context(
98        &self,
99        value: &Value,
100        context: &mut Option<&mut dyn Context>,
101    ) -> Result<Value> {
102        let mut left_val = value.clone();
103        for op in &self.left_ops {
104            left_val = op.apply_with_context(&left_val, context)?;
105        }
106
107        let mut right_val = value.clone();
108        for op in &self.right_ops {
109            right_val = op.apply_with_context(&right_val, context)?;
110        }
111
112        Ok(Value::Bool(left_val != right_val))
113    }
114
115    fn description(&self) -> String {
116        "not equals".to_string()
117    }
118
119    fn as_any(&self) -> &dyn Any {
120        self
121    }
122}
123
124/// Less than comparison operation
125///
126/// Compares if the left value is less than the right value.
127pub struct LtOperation {
128    /// Operations that produce the left operand
129    pub left_ops: Vec<Box<dyn Operation + Send + Sync>>,
130    /// Operations that produce the right operand
131    pub right_ops: Vec<Box<dyn Operation + Send + Sync>>,
132}
133
134impl LtOperation {
135    /// Creates a new less than operation with the given operand operations
136    pub fn new(
137        left_ops: Vec<Box<dyn Operation + Send + Sync>>,
138        right_ops: Vec<Box<dyn Operation + Send + Sync>>,
139    ) -> Self {
140        Self {
141            left_ops,
142            right_ops,
143        }
144    }
145}
146
147impl Operation for LtOperation {
148    fn apply(&self, value: &Value) -> Result<Value> {
149        let mut context = None;
150        self.apply_with_context(value, &mut context)
151    }
152
153    fn apply_with_context(
154        &self,
155        value: &Value,
156        context: &mut Option<&mut dyn Context>,
157    ) -> Result<Value> {
158        let mut left_val = value.clone();
159        for op in &self.left_ops {
160            left_val = op.apply_with_context(&left_val, context)?;
161        }
162
163        let mut right_val = value.clone();
164        for op in &self.right_ops {
165            right_val = op.apply_with_context(&right_val, context)?;
166        }
167
168        let ordering = compare_values(&left_val, &right_val)?;
169        Ok(Value::Bool(ordering == std::cmp::Ordering::Less))
170    }
171
172    fn description(&self) -> String {
173        "less than".to_string()
174    }
175
176    fn as_any(&self) -> &dyn Any {
177        self
178    }
179}
180
181/// Less than or equal comparison operation
182///
183/// Compares if the left value is less than or equal to the right value.
184pub struct LeOperation {
185    /// Operations that produce the left operand
186    pub left_ops: Vec<Box<dyn Operation + Send + Sync>>,
187    /// Operations that produce the right operand
188    pub right_ops: Vec<Box<dyn Operation + Send + Sync>>,
189}
190
191impl LeOperation {
192    /// Creates a new less than or equal operation with the given operand operations
193    pub fn new(
194        left_ops: Vec<Box<dyn Operation + Send + Sync>>,
195        right_ops: Vec<Box<dyn Operation + Send + Sync>>,
196    ) -> Self {
197        Self {
198            left_ops,
199            right_ops,
200        }
201    }
202}
203
204impl Operation for LeOperation {
205    fn apply(&self, value: &Value) -> Result<Value> {
206        let mut context = None;
207        self.apply_with_context(value, &mut context)
208    }
209
210    fn apply_with_context(
211        &self,
212        value: &Value,
213        context: &mut Option<&mut dyn Context>,
214    ) -> Result<Value> {
215        let mut left_val = value.clone();
216        for op in &self.left_ops {
217            left_val = op.apply_with_context(&left_val, context)?;
218        }
219
220        let mut right_val = value.clone();
221        for op in &self.right_ops {
222            right_val = op.apply_with_context(&right_val, context)?;
223        }
224
225        let ordering = compare_values(&left_val, &right_val)?;
226        Ok(Value::Bool(ordering != std::cmp::Ordering::Greater))
227    }
228
229    fn description(&self) -> String {
230        "less than or equal".to_string()
231    }
232
233    fn as_any(&self) -> &dyn Any {
234        self
235    }
236}
237
238/// Greater than comparison operation
239///
240/// Compares if the left value is greater than the right value.
241pub struct GtOperation {
242    /// Operations that produce the left operand
243    pub left_ops: Vec<Box<dyn Operation + Send + Sync>>,
244    /// Operations that produce the right operand
245    pub right_ops: Vec<Box<dyn Operation + Send + Sync>>,
246}
247
248impl GtOperation {
249    /// Creates a new greater than operation with the given operand operations
250    pub fn new(
251        left_ops: Vec<Box<dyn Operation + Send + Sync>>,
252        right_ops: Vec<Box<dyn Operation + Send + Sync>>,
253    ) -> Self {
254        Self {
255            left_ops,
256            right_ops,
257        }
258    }
259}
260
261impl Operation for GtOperation {
262    fn apply(&self, value: &Value) -> Result<Value> {
263        self.apply_with_context(value, &mut None)
264    }
265
266    fn apply_with_context(
267        &self,
268        value: &Value,
269        context: &mut Option<&mut dyn Context>,
270    ) -> Result<Value> {
271        let mut left_val = value.clone();
272        for op in &self.left_ops {
273            left_val = op.apply_with_context(&left_val, context)?;
274        }
275
276        let mut right_val = value.clone();
277        for op in &self.right_ops {
278            right_val = op.apply_with_context(&right_val, context)?;
279        }
280
281        let ordering = compare_values(&left_val, &right_val)?;
282        Ok(Value::Bool(ordering == std::cmp::Ordering::Greater))
283    }
284
285    fn description(&self) -> String {
286        "greater than".to_string()
287    }
288
289    fn as_any(&self) -> &dyn Any {
290        self
291    }
292}
293
294/// Greater than or equal comparison operation
295///
296/// Compares if the left value is greater than or equal to the right value.
297pub struct GeOperation {
298    /// Operations that produce the left operand
299    pub left_ops: Vec<Box<dyn Operation + Send + Sync>>,
300    /// Operations that produce the right operand
301    pub right_ops: Vec<Box<dyn Operation + Send + Sync>>,
302}
303
304impl GeOperation {
305    /// Creates a new greater than or equal operation with the given operand operations
306    pub fn new(
307        left_ops: Vec<Box<dyn Operation + Send + Sync>>,
308        right_ops: Vec<Box<dyn Operation + Send + Sync>>,
309    ) -> Self {
310        Self {
311            left_ops,
312            right_ops,
313        }
314    }
315}
316
317impl Operation for GeOperation {
318    fn apply(&self, value: &Value) -> Result<Value> {
319        let mut context = None;
320        self.apply_with_context(value, &mut context)
321    }
322
323    fn apply_with_context(
324        &self,
325        value: &Value,
326        context: &mut Option<&mut dyn Context>,
327    ) -> Result<Value> {
328        let mut left_val = value.clone();
329        for op in &self.left_ops {
330            left_val = op.apply_with_context(&left_val, context)?;
331        }
332
333        let mut right_val = value.clone();
334        for op in &self.right_ops {
335            right_val = op.apply_with_context(&right_val, context)?;
336        }
337
338        let ordering = compare_values(&left_val, &right_val)?;
339        Ok(Value::Bool(ordering != std::cmp::Ordering::Less))
340    }
341
342    fn description(&self) -> String {
343        "greater than or equal".to_string()
344    }
345
346    fn as_any(&self) -> &dyn Any {
347        self
348    }
349}