Skip to main content

reductstore/storage/query/condition/operators/arithmetic/
div.rs

1// Copyright 2025 ReductSoftware UG
2// Licensed under the Business Source License 1.1
3
4use crate::storage::query::condition::value::Div as DivTrait;
5use crate::storage::query::condition::value::Value;
6use crate::storage::query::condition::{Boxed, BoxedNode, Context, Node};
7use reduct_base::error::ReductError;
8use reduct_base::unprocessable_entity;
9
10/// A node representing an arithmetic division operation.
11pub(crate) struct Div {
12    operands: Vec<BoxedNode>,
13}
14
15impl Node for Div {
16    fn apply(&mut self, context: &Context) -> Result<Value, ReductError> {
17        let value_1 = self.operands[0].apply(context)?;
18        let value_2 = self.operands[1].apply(context)?;
19        value_1.divide(value_2)
20    }
21
22    fn print(&self) -> String {
23        format!("Div({:?}, {:?})", self.operands[0], self.operands[1])
24    }
25}
26
27impl Boxed for Div {
28    fn boxed(operands: Vec<BoxedNode>) -> Result<BoxedNode, ReductError> {
29        if operands.len() != 2 {
30            return Err(unprocessable_entity!("$div requires exactly two operands"));
31        }
32
33        Ok(Box::new(Div::new(operands)))
34    }
35}
36
37impl Div {
38    pub fn new(operands: Vec<BoxedNode>) -> Self {
39        Self { operands }
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46    use crate::storage::query::condition::constant::Constant;
47    use crate::storage::query::condition::value::Value;
48    use rstest::rstest;
49
50    #[rstest]
51    fn apply_ok() {
52        let mut sub = Div::new(vec![
53            Constant::boxed(Value::Int(1)),
54            Constant::boxed(Value::Int(2)),
55        ]);
56        assert_eq!(sub.apply(&Context::default()).unwrap(), Value::Float(0.5));
57    }
58
59    #[rstest]
60    fn apply_bad() {
61        let mut sub = Div::new(vec![
62            Constant::boxed(Value::Int(1)),
63            Constant::boxed(Value::String("foo".to_string())),
64        ]);
65        assert_eq!(
66            sub.apply(&Context::default()),
67            Err(unprocessable_entity!("Cannot divide by string"))
68        );
69    }
70
71    #[rstest]
72    fn apply_empty() {
73        let op = Div::boxed(vec![]);
74        assert_eq!(
75            op.err(),
76            Some(unprocessable_entity!("$div requires exactly two operands"))
77        );
78    }
79
80    #[rstest]
81    fn print() {
82        let op = Div::new(vec![
83            Constant::boxed(Value::Bool(true)),
84            Constant::boxed(Value::Bool(true)),
85        ]);
86        assert_eq!(op.print(), "Div(Bool(true), Bool(true))");
87    }
88}